/*
 * Planeta.h
 *
 *  Created on: 09/01/2010
 *      Author: San Martín, Matías I.
 */

#ifndef PLANETA_ENPLANETA_AGOPISJOEWJODSJOJRGWAIHLDSJOXCMBNRQEK_H_
#define PLANETA_ENPLANETA_AGOPISJOEWJODSJOJRGWAIHLDSJOXCMBNRQEK_H_

#include <vector>
#include <sstream>

#include "../../../Framework/IO/log.h"

#include "../Common/InformacionPlaneta.h"

#include "../../Common/CommonTypes.h"
#include "../../Common/Mensajes/MensajesCommonTypes.h"
#include "../../Common/Mensajes/MensajeAplicacion.h"
#include "../../Utiles/Posicion.h"

#include "../../../Middleware/Common/IdPlaneta.h"

#include "../../../Middleware/EnPlaneta/MsjEmisor.h"
#include "../../../Middleware/EnPlaneta/MsjReceptor.h"

#include "../Common/Flota.h"

#include "ColeccionFlotas.h"

using namespace aplicacion;

namespace aplicacion {
namespace planeta {

typedef ColeccionFlotas t_flotas;

class Planeta {
//------------------------------ CONSTANTES ------------------------------
public:

	//TODO HACER CONFIGURABLE
	/** Path a donde se crean los fifo de comunicacion con el middleware */
	static const std::string PATH_FIFO;

	/** Extension del fd */
	static const std::string EXT_FIFO;


	/** Multiplicador que define la cantidad de naves iniciales del
	 * planeta en función el tamaño */
	static const unsigned MULTIPLICADOR_NAVES = 10; //TODO HACER CONFIGURABLE

	/** Multiplicador de naves por segundo, es decir, que proporción de naves
	 * respecto del tamaño del planeta se genera por segundo
	 */
	static const unsigned MULTIPLICADOR_NAVES_SEG = 1; //TODO HACER CONFIGURABLE

	/**
	 * Cantidad de naves que se deben generar (desde el ultimo aviso) para dar
	 * aviso del estado a los jugadores (sincronización)
	 */
	static const unsigned CANT_NAVES_GENERADAS_AVISO = 50; //TODO HACER CONFIGURABLE

	/**
	 * Cantidad de naves que deben arribar (desde el ultimo aviso) para dar
	 * aviso del estado a los jugadores (sincronización).
	 * Notar que en caso de que termine de llegar una flota se da aviso
	 * igualmente (no necesariamente respetando este valor).
	 */
	static const unsigned CANT_NAVES_ARRIBO_AVISO = 10; //TODO HACER CONFIGURABLE

	/**
	 * Factor que determina el "tamaño" del planeta junto con el valor asociado
	 * InformacionPlaneta._tamanio. Influye en cuanto se distribuyen las naves
	 * de una flota generada en el planeta
	 */
	static const double FACTOR_ESCALA_TAMANIO = 10.;


//--------------------------- ATRIBUTOS ------------------------------------
private:

	//-------------- estado del planeta (aplicación) ------
	InformacionPlaneta _info;

	/** flotas dirigidas al planeta */
	t_flotas _flotas;

	/** tiempo (de juego para el planeta) que indica el momento de la consulta */
	T_TIEMPO _tahora;

	//------------ middleware -------------------------
	MsjReceptor* _receptor;
	MsjEmisor* _emisor;
	int _pipeRecepcion;

	//----------- estado del proceso ------------------
	/** indica si se debe ejecutar el proceso */
	bool _ejecutar;

	/** se establece en verdadero cuando se cambian (se agregan o eliminan)
	 *  las flotas asociadas al planeta*/
	bool _cambiaronFlotas;


//------------------------------ METODOS ------------------------------
public:
	Planeta(IdPlaneta identificador, T_TAMANIO_PLANETA tamanio,
			Posicion posicion);
	virtual ~Planeta();

	/** solo para testing */
	static std::string getFdName(IdPlaneta id)
	{
		std::stringstream stm;
		stm << PATH_FIFO << id.getUid() << "." << EXT_FIFO;
		return stm.str();
	}

	/**
	 * Inicializa el planeta con las estructuras necesarias para usarlo
	 * TODO talvez conviene que se obtengan con la registry
	 */
	void init (MsjReceptor* receptor, MsjEmisor* emisor);

	/**
	 * permite iniciar el ciclo de trabajo del planeta
	 */
	void run();

	/**
	 * Permite detener el ciclo de trabajo del planeta
	 */
	void stop();

	std::string getFdName();

protected:

	/**
	 * Envía un mensaje de notificación de la cantidad de naves del planeta
	 * (nave generada) a los jugadores
	 */
	void notificarCantidadNaves();

	/**
	 * Envía un mensaje de notificación de arribo a los jugadores
	 */
	void notificarArribaronNaves(const IdFlota& flotaArribo, size_t cantidadNavesFlota);

	void cambiarDuenio(const IdJugador& nuevoDuenio);

	/**
	 * Envía un mensaje de notificación de cambio de dueño
	 */
	void notificarCambioDuenio(const IdJugador& duenioAnterior);

	/**
	 * Genera arribo de las naves debido al paso del tiempo indicado
	 *
	 * @param notificar indica que se debe enviar la notificacion de los arribos.
	 * 					NOTA: si una flota termina de arribar, se envia la
	 * 							notificacion por mas de que este parametro
	 * 							sea falso
	 */
	void arribarNaves(T_TIEMPO tiempo, bool notificar);

	/**
	 * Genera las naves debido al paso del tiempo indicado
	 */
	void generarNaves(T_TIEMPO tiempoPaso);

	/**
	 * Recibe un mensaje desde el pipe y carga los datos en el mensaje indicado
	 */
	void recibirMensaje(MensajeAplicacion& mensaje);

	/** permite procesar un mensaje recibido.
	 *
	 * @param mensaje mensaje recibido
	 * @param tamanio tamaño del mensaje recibido
	 */
	virtual void procesarMensaje(MensajeAplicacion& mensaje);

	/**
	 * Espera especificamente por el mensaje de start y lo procesa.
	 * Si se recibe cualquier otro mensaje que no es el esperado, se descarta
	 * y se continua esperando
	 *
	 * @return true si se recibio el mensaje.
	 * FIXME en deberia lanzar excepcion si falla la recepcion, lo hago asi
	 * 		por simplicidad
	 */
	bool recibirMsjStart();

	void ejecutarAbandonaJugador(MensajeAplicacion& mensaje);
	void ejecutarAvisarCrearFlota(MensajeAplicacion& mensaje);
	void ejecutarCreacionFlota(MensajeAplicacion& mensaje);
	void ejecutarCambioDueno(MensajeAplicacion& mensaje);
	void ejecutarAvisarCambiarRumboFlota(MensajeAplicacion& mensaje);
	void ejecutarCambiarRumboFlota(MensajeAplicacion& mensaje);

	/**
	 * Actualiza la fuente (asignando el id del planeta) y envía el mensaje
	 * al juego asociado al dueño
	 */
	int enviarAJuego(MensajeAplicacion& mensaje);

	/**
	 * Actualiza la fuente (asignando el id del planeta) y el destino (según el
	 * indicado) y envía el mensaje destino
	 */
	int enviarAPlaneta(IdPlaneta destino, MensajeAplicacion& mensaje);
};

} //namespace planeta
} //namespace aplicacion

#endif /* PLANETA_ENPLANETA_AGOPISJOEWJODSJOJRGWAIHLDSJOXCMBNRQEK_H_ */
